﻿// Inner Fire 游戏引擎库
// Transform - 游戏变形对象
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层（4）
// 指定对象的Position，Scale，Rotation的项目。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-01-21

#include "transform.h"
#include <game/object/game_object.h>
#include <game/physics/physics_math.h>

using namespace DirectX;

namespace ifire::game {

Transform::Transform(GameObject* owner)
    : parent(nullptr)
    , game_object(owner)
    , mat()
    , position(0.0f, 0.0f, 0.0f)
    , rotation(0.0f, 0.0f, 0.0f, 0.0f)
    , scale(1.0f, 1.0f, 1.0f) {}

void Transform::SetRotationEular(const IVec3& value) {
  float x = XMConvertToRadians(value.x);
  float y = XMConvertToRadians(value.y);
  float z = XMConvertToRadians(value.z);
  XMStoreFloat4(&rotation, XMQuaternionRotationRollPitchYaw(x, y, z));
  game_object->UpdateTransform();
}

IMat Transform::BuildMatrix() {
  return mat = XMMatrixAffineTransformation(XMLoadFloat3(&scale), VEC0,
             XMLoadFloat4(&rotation), XMLoadFloat3(&position));
}

IMat Transform::SetWorldMatrix(
    const IVec3& _position, const IVec3& _rotation, const IVec3& _scale) {
  SetPosition(_position);
  SetRotationEular(_rotation);
  SetScale(_scale);
  return BuildMatrix();
}

void Transform::SetWorldMatrix(FMat _mat) {
  // 直接设置世界矩阵
  mat = _mat;
  // 拆分世界矩阵到变量
  XMVECTOR scl, rot, pos;
  XMMatrixDecompose(&scl, &rot, &pos, mat);
  XMStoreFloat3(&position, pos);
  XMStoreFloat4(&rotation, rot);
  XMStoreFloat3(&scale, scl);
}

IVec3 Transform::GetParentPosition() const {
  return parent == nullptr ? IVec3() : parent->GetPosition();
}

IVec4 Transform::GetParentRotation() const {
  return parent == nullptr ? IVec4() : parent->GetRotation();
}

IVec3 Transform::GetParentScale() const {
  return parent == nullptr ? IVec3(1.0f, 1.0f, 1.0f) : parent->GetScale();
}

IVec3 Transform::GetPosition() const { return position; }

IVec4 Transform::GetRotation() const { return rotation; }

IVec3 Transform::GetRotationEular() const {
  return imath::QuaternionToEulerDegree(rotation);
}

IVec3 Transform::GetScale() const { return scale; }

void Transform::SetPosition(const IVec3& value) {
  position = value;
  game_object->UpdateTransform();
}

void Transform::SetScale(const IVec3& value) {
  scale = value;
  game_object->UpdateTransform();
}

IVec3 Transform::LookTowardLerp(const IVec3& direction, float max_angle) {
  // 1. 归一化输入方向向量
  // 这里需要取反，因为Direct的坐标系的关系
  IVec target_dir = -XMVector3Normalize(XMLoadFloat3(&direction));

  // 2. 获取当前旋转四元数
  IVec current_rot = XMLoadFloat4(&rotation);

  // 3. 计算目标旋转（Z轴对齐目标方向，Y轴向上）
  IVec target_rot = imath::QuaternionLookTo(target_dir);

  // 4. 计算当前方向与目标方向的夹角（弧度）
  float dot = XMVectorGetX(XMQuaternionDot(current_rot, target_rot));
  float theta = acosf(fminf(fabsf(dot), 1.0f));
  // 角度转为弧度
  max_angle = XMConvertToRadians(max_angle);
  // 根据最大允许角度 max_angle 计算插值比例：
  float t = (theta <= max_angle) ? 1.0f : (imath::Min(1.0f, max_angle / theta));

  // 6. 球面线性插值（SLERP）
  IVec result_rot = XMQuaternionSlerp(current_rot, target_rot, t);

  // 7. 存储结果
  XMStoreFloat4(&rotation, result_rot);

  // 更新对象
  game_object->UpdateTransform();

  return imath::QuaternionToEuler(result_rot);
}

void Transform::SetSpring(IVec3 start, IVec3 end, float width) {
  // 计算得到变换
  auto trans = physics_math::CalcSpringTransform(start, end, width);
  // 重新设置变换矩阵
  XMStoreFloat3(&position, trans.position);
  XMStoreFloat4(&rotation, trans.rotation);
  XMStoreFloat3(&scale, trans.scale);
  // 更新对象
  game_object->UpdateTransform();
}

IVec3 Transform::GetForward() const {
  // 分解矩阵获取旋转四元数（忽略缩放和平移的影响）
  IVec scale;
  IVec rotationQuat;
  IVec translation;
  XMMatrixDecompose(&scale, &rotationQuat, &translation, mat);

  // 定义局部坐标系的前向向量（Z轴方向）
  IVec localForward = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);

  // 使用四元数旋转局部前向向量
  IVec worldForward = XMVector3Rotate(localForward, rotationQuat);

  // 归一化结果向量
  worldForward = XMVector3Normalize(worldForward);

  // 转换回常规IVec3格式
  IVec3 result;
  XMStoreFloat3(&result, worldForward);

  return result;
}

static IMat CreateRotationFromForward(
    IVec forwardVec, IVec upVec = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f)) {
  // 归一化输入向量
  forwardVec = XMVector3Normalize(forwardVec);
  upVec = XMVector3Normalize(upVec);

  // 计算右向量（局部坐标系X轴）
  IVec rightVec = XMVector3Cross(upVec, forwardVec);
  rightVec = XMVector3Normalize(rightVec);

  // 重新计算正交的Up向量（局部坐标系Y轴）
  upVec = XMVector3Cross(forwardVec, rightVec);

  // 构建旋转矩阵
  IMat rotationMatrix(rightVec, // 矩阵第一行（X轴）
      upVec,                    // 矩阵第二行（Y轴）
      forwardVec,               // 矩阵第三行（Z轴）
      XMVectorSet(0, 0, 0, 1)   // 第四行
  );

  return rotationMatrix;
}

// 变换方向向量（忽略平移分量）
IVec3 Transform::TransformDirection(const IVec3& direction) const {
  IVec v = XMLoadFloat3(&direction);

  // 使用TransformNormal（自动忽略平移分量）
  v = XMVector3TransformNormal(v, mat);

  // 存储结果
  return StoreF3(v);
}

IVec3 Transform::TransformPosition(const IVec3& position) const {
  IVec v = XMLoadFloat3(&position);

  // 使用TransformNormal（自动忽略平移分量）
  v = XMVector3TransformCoord(v, mat);

  // 存储结果
  return StoreF3(v);
}

IVec3 Transform::TransformForward(IVec3 vec) const {
  // 1. 提取世界矩阵的旋转部分（去除缩放）
  XMVECTOR scale;
  XMVECTOR rotationQuat;
  XMVECTOR translation;
  XMMatrixDecompose(&scale, &rotationQuat, &translation, mat);

  // 2. 将局部向量转换到世界空间
  XMMATRIX rotationMatrix = XMMatrixRotationQuaternion(rotationQuat);
  IVec worldDirection =
      XMVector3TransformNormal(XMLoadFloat3(&vec), rotationMatrix);

  // 3. 获取对象的正对方向（Forward方向）
  IVec forward = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); // Z轴是正对方向
  forward = XMVector3TransformNormal(forward, rotationMatrix);
  forward = XMVector3Normalize(forward);

  // 4. 将世界空间向量投影到正对方向
  IVec projectedVector = XMVector3Dot(worldDirection, forward) * forward;

  return StoreF3(projectedVector);
}

IVec3 Transform::WorldToLocal(IVec3 world_position) const {
  // 计算逆旋转
  XMVECTOR invRotation = XMQuaternionInverse(XMLoadFloat4(&rotation));

  // 计算相对于对象的局部位置
  XMVECTOR local_pos = XMLoadFloat3(&world_position) - XMLoadFloat3(&position);
  local_pos = XMVector3Rotate(local_pos, invRotation);

  // 如果需要考虑缩放，可以添加这步
  local_pos = local_pos / XMLoadFloat3(&scale);

  return StoreF3(local_pos);
}

} // namespace ifire::game
